#include "record_snap_storage.h"
#include <atomic>
#include <memory>
#include <sstream>
#include <iomanip>
#include <chrono>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <libgen.h>
#include "utils_noncopyable.h"
#include "media_snap.h"
#include "utils_log.h"
#include "common_config_manager.h"
#include "record_index_writer.h"
#include "utils_file_ex.h"
#include "common_event.h"
#include "record_utils.h"
#include "storage_manager.h"

namespace El {
namespace Record {

ISnapStorage &ISnapStorage::GetInstance()
{
    static CSnapStorage instance;
    return instance;
}

CSnapStorage::CSnapStorage()
{
    // 初始化默认配置
    auto config = Common::ConfigManager::GetInstance().GetConfig("/storage");
    if (!config.empty() && config.contains("mountPath")) {
        storePath_ = config["mountPath"].get<std::string>();
    } else {
        storePath_ = "/mnt/udisk";
        EL_ERROR("storage config is empty");
    }
    PathUtils::GetInstance().SetStorePath(storePath_);
}

bool CSnapStorage::Start()
{
    return true;
}

void CSnapStorage::Stop() {}

int32_t CSnapStorage::manualSnap(int32_t ch)
{
    EL_DEBUG("Manual snap for channel {}", ch);

    Storage::DeviceStatus status;
    Storage::IStorageManager::GetInstance().GetDefaultUdiskStatus(status);
    if (status != Storage::DeviceStatus::ERR_MOUNTED && status != Storage::DeviceStatus::ERR_CAPACITY_NORMAL) {
        EL_ERROR("Udisk is not normal {}", Storage::DeviceStatusToString(status));
        return (int32_t)status;
    }

    // 获取大图抓图实例
    auto &snapMain = Media::ISnap::GetInstance(ch, MEDIA_VIDEO_ENC_STREAM_SNAPSHOT);
    // 获取小图抓图实例
    auto &snapThumb = Media::ISnap::GetInstance(ch, MEDIA_VIDEO_ENC_STREAM_SMALL_SNAPSHOT);

    std::atomic<int> completedSnaps{0};
    std::mutex mtx;
    std::condition_variable cv;
    Media::MediaFramePtr mainFrame, thumbFrame;
    bool mainCompleted = false;
    bool thumbCompleted = false;

    // 注册大图回调
    int32_t handleMain = snapMain.Register([&](const Media::MediaFramePtr &frame) {
        {
            std::lock_guard<std::mutex> lock(mtx);
            mainFrame = frame;
            mainCompleted = true;
        }
        cv.notify_one();
    });

    // 注册小图回调
    int32_t handleThumb = snapThumb.Register([&](const Media::MediaFramePtr &frame) {
        {
            std::lock_guard<std::mutex> lock(mtx);
            thumbFrame = frame;
            thumbCompleted = true;
        }
        cv.notify_one();
    });

    if (handleMain < 0 || handleThumb < 0) {
        EL_ERROR("Failed to register snap callbacks");
        return false;
    }

    // 同时触发大小图抓图
    if (!snapMain.ManualSnap() || !snapThumb.ManualSnap()) {
        EL_ERROR("Failed to trigger manual snap");
        snapMain.Unregister(handleMain);
        snapThumb.Unregister(handleThumb);
        return false;
    }

    // 等待两张图片都完成
    {
        std::unique_lock<std::mutex> lock(mtx);
        if (!cv.wait_for(lock, std::chrono::seconds(5), [&]() { return mainCompleted && thumbCompleted; })) {
            EL_ERROR("Timeout waiting for snaps, main: {}, thumb: {}", mainCompleted, thumbCompleted);
            snapMain.Unregister(handleMain);
            snapThumb.Unregister(handleThumb);
            return false;
        }
    }

    // 保存图片
    bool success = SaveImageFile(ch, 0, mainFrame, false) && SaveImageFile(ch, 0, thumbFrame, true);

    // 同步文件
    sync();
    EL_DEBUG("Synced current picture file for channel {}", ch);

    // 清理资源
    snapMain.Unregister(handleMain);
    snapThumb.Unregister(handleThumb);

    if (success) {
        return ERR_OK;
    }

    return -1;
}

bool CSnapStorage::SaveImageFile(int32_t ch, int32_t type, const Media::MediaFramePtr &frame, bool isThumbnail)
{
    if (!frame || frame->GetLength() == 0) {
        EL_ERROR("Invalid {} frame", isThumbnail ? "thumbnail" : "image");
        return false;
    }

    // 获取当前时间
    auto now = std::chrono::system_clock::now();
    time_t timestamp = std::chrono::system_clock::to_time_t(now);

    // 生成文件路径
    std::string filename =
        PathUtils::GetInstance().GenerateFilename(timestamp, ch, type, isThumbnail ? "thumbnails" : "images", ".jpg");
    if (filename.empty()) {
        return false;
    }

    // 保存文件
    std::ofstream file(filename, std::ios::binary);
    if (!file.is_open()) {
        EL_ERROR("Failed to open {} file: {}", isThumbnail ? "thumbnail" : "image", filename);
        return false;
    }

    file.write(reinterpret_cast<const char *>(frame->GetBuffer()), frame->GetLength());
    file.close();

    if (!isThumbnail) {
        // Create image index entry
        char *baseFilename = basename(const_cast<char *>(filename.c_str()));
        nlohmann::json imageIndex = {
            {"filename", std::string(baseFilename)},
            {"timestamp", std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())},
            {"channel", ch},
            {"file_size", frame->GetLength()}};

        // 确保使用绝对路径
        std::string absolutePath =
            PathUtils::GetInstance().GenerateIndexPath(std::chrono::system_clock::to_time_t(now));
        IndexWriter::GetInstance().WriteImageIndex(absolutePath, imageIndex);
    }

    EL_INFO("Saved {} to: {}", isThumbnail ? "thumbnail" : "image", filename);
    return true;
}

} // namespace Record
} // namespace El